package com.gdust.spzx.common.log.aspect;

import com.gdust.spzx.common.log.service.AsyncOperLogService;
import com.gdust.spzx.common.log.utils.LogUtil;
import com.gdust.spzx.common.log.annotation.Log;
import com.gdust.hzx.model.entity.system.SysOperLog;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;


/**
 * ClassName: LogAspect
 * Package: com.gdust.spzx.common.aspect
 * Description: 定义一个切面类，在该类中提供一个环绕通知方法，用于记录操作日志。
 *
 * @Author syun
 * @Create 2024/12/24 20:33
 * @Version 1.0
 */
@Aspect  // 表明这是一个切面类
@Component  // 将该类标注为 Spring 组件
@Slf4j  // 使用Lombok提供的日志注解，简化日志记录
public class LogAspect {

    @Autowired
    private AsyncOperLogService asyncOperLogService;  // 异步保存操作日志的服务

    /**
     * 环绕通知方法
     *
     * 该方法会在标注了 @Log 注解的方法前后执行，执行过程中负责记录操作日志信息。
     * 通过使用 `ProceedingJoinPoint` 可以控制方法的执行过程，并在方法执行后保存日志数据。
     *
     * @param joinPoint 连接点，表示被拦截的目标方法
     * @param sysLog    从拦截到的方法上获取的 @Log 注解对象，用于提取注解中的配置信息
     * @return Object   目标方法的执行结果
     */
    @Around(value = "@annotation(sysLog)")  // 定义环绕通知，拦截使用 @Log 注解的方法
    public Object doAroundAdvice(ProceedingJoinPoint joinPoint, Log sysLog) {
        // 1. 构建前置参数，创建日志记录实体对象 SysOperLog
        SysOperLog sysOperLog = new SysOperLog();

        // 2. 处理方法执行前的日志记录，封装请求信息
        LogUtil.beforeHandleLog(sysLog, joinPoint, sysOperLog);

        Object proceed = null;
        try {
            // 3. 执行业务方法（目标方法）
            proceed = joinPoint.proceed();

            // 4. 处理方法执行后的日志记录，封装响应信息，状态为成功（0）
            LogUtil.afterHandleLog(sysLog, proceed, sysOperLog, 0, null);

        } catch (Throwable e) {
            // 5. 如果业务方法执行时发生异常，捕获并处理
            e.printStackTrace();  // 打印异常信息

            // 6. 处理异常后的日志记录，封装异常信息，状态为失败（1）
            LogUtil.afterHandleLog(sysLog, proceed, sysOperLog, 1, e.getMessage());

            // 7. 抛出运行时异常，确保异常继续向上传递
            throw new RuntimeException();
        }

        // 8. 异步保存日志数据到数据库
        asyncOperLogService.saveSysOperLog(sysOperLog);

        // 9. 返回目标方法的执行结果
        return proceed;
    }

}
